import math

import mediapipe as mp
import cv2
import numpy as np

def line_equation(p1, p2):
    """计算中轴线的方程 Ax + By + C = 0"""
    A = p2[1] - p1[1]
    B = p1[0] - p2[0]
    C = A * p1[0] + B * p1[1]
    return A, B, -C

def fit_line(points):
    """用最小二乘法拟合直线"""
    points = np.array(points)
    A = np.vstack([points[:, 0], np.ones(len(points))]).T
    m, c = np.linalg.lstsq(A, points[:, 1], rcond=None)[0]
    return m, c

def calculate_x_range(m, c, y_min, y_max):
    """根据y值范围计算x范围"""
    if m != 0:  # 确保斜率不为零
        x_min = (y_min - c) / m
        x_max = (y_max - c) / m
    else:  # 斜率为零，即水平线
        x_min = x_max = 0
    return x_min, x_max


def plot_line_segment(image, m, c, y_min, y_max, color=(0, 0, 255), thickness=2):
    """根据y的最小值和最大值绘制直线段"""
    # 计算x范围
    x_min, x_max = calculate_x_range(m, c, y_min, y_max)

    # 确保x范围在图像的实际范围内
    x_min = max(0, min(image.shape[1] - 1, x_min))
    x_max = max(0, min(image.shape[1] - 1, x_max))

    # 计算直线在x范围内的y值
    x_range = np.linspace(x_min, x_max, 100)
    y_range = m * x_range + c

    # 绘制直线段
    for i in range(len(x_range) - 1):
        start_point = (int(x_range[i]), int(y_range[i]))
        end_point = (int(x_range[i + 1]), int(y_range[i + 1]))
        # 确保线段在图像范围内
        if (0 <= start_point[0] < image.shape[1] and 0 <= start_point[1] < image.shape[0] and
                0 <= end_point[0] < image.shape[1] and 0 <= end_point[1] < image.shape[0]):
            cv2.line(image, start_point, end_point, color, thickness)


def distance_point_to_line(point1, point2, point3):
    """
    计算点1(px, py)到直线2,3(x1, y1)-(x2, y2)的距离
    """
    # 直线的两个点： (x1, y1) 和 (x2, y2)
    # 点 (px, py) 是我们要计算的点
    px, py = point1
    x1,y1 = point2
    x2,y2 = point3
    # 计算直线的方向向量
    line_vector_x = x2 - x1
    line_vector_y = y2 - y1

    # 计算点到直线的垂直距离公式
    num = abs(line_vector_y * px - line_vector_x * py + x2 * y1 - y2 * x1)
    denom = math.sqrt(line_vector_y ** 2 + line_vector_x ** 2)

    return num / denom

def reflect_point_around_line(x, y, A, B, C):
    """计算点关于直线的对称点"""
    d = (A * x + B * y + C) / (A**2 + B**2)
    x_reflected = x - 2 * A * d
    y_reflected = y - 2 * B * d
    return (x_reflected, y_reflected)
def calculate_distance(p1, p2):
    """计算两个点之间的欧氏距离"""
    return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

def calculate_total_distance(lip_landmarks, reflected_points):
    """计算特定顺序下的距离和"""
    total_distance = 0
    num_points = len(lip_landmarks)
    for i in range(num_points):
        # 当前点和对称点
        lip_point = lip_landmarks[i]
        reflected_point = reflected_points[num_points - 1 - i]
        # 计算距离
        distance = calculate_distance(lip_point, reflected_point)
        # 累加距离
        print(distance)
        total_distance += distance
    return total_distance

def lipClassification(image_path):
# 构建脸部特征提取对象
    mp_face_mesh = mp.solutions.face_mesh

    face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True,
                                      max_num_faces=1,
                                      refine_landmarks=True,
                                      min_detection_confidence=0.5)

    # 构建面部绘图对象
    mp_drawing = mp.solutions.drawing_utils
    mp_drawing_styles = mp.solutions.drawing_styles
    # 读取图片
    image = cv2.imread(image_path)
    # 缩放到目标大小
    resized_face = cv2.resize(image, (image.shape[1] //2, image.shape[0] // 2))
    # 再送入 Mediapipe
    results = face_mesh.process(cv2.cvtColor(resized_face, cv2.COLOR_BGR2RGB))

    if results.multi_face_landmarks:
        for face_landmarks in results.multi_face_landmarks:
            lip_indices = [37, 39, 40, 185, 61, 146, 91, 181, 84, 76, 62, 78, 95, 88, 178, 87, 77, 90, 180, 85,
                           315, 404, 320, 307, 317, 402, 318, 324, 308, 292, 306, 314, 405, 321, 375, 291, 409, 270, 269, 267]#共四十个点
            lip_landmarks = []
            for idx in lip_indices:
                landmark = face_landmarks.landmark[idx]
                lip_landmarks.append((
                    int(landmark.x * image.shape[1]),
                    int(landmark.y * image.shape[0])
                ))
            # 画嘴部
            lip_landmarks_show = []
            for idx in mp_face_mesh.FACEMESH_LIPS:
                lip_landmarks_show.append([
                    int(face_landmarks.landmark[idx[0]].x * image.shape[1]),
                    int(face_landmarks.landmark[idx[0]].y * image.shape[0])
                ])
                lip_landmarks_show.append([
                    int(face_landmarks.landmark[idx[1]].x * image.shape[1]),
                    int(face_landmarks.landmark[idx[1]].y * image.shape[0])
                ])
            for i in range(0, len(lip_landmarks_show) - 1, 2):
                pt1 = tuple(lip_landmarks_show[i])
                pt2 = tuple(lip_landmarks_show[i + 1])
                cv2.line(image, pt1, pt2, (255, 255, 255), 1)

                # 绘制嘴部关键点
            for point in lip_landmarks_show:
                cv2.circle(image, tuple(point), 2, (255, 255, 255), -1)


            # # 提取面部中轴线（通常是 4 和 8 点的中点）
            nose_tip = face_landmarks.landmark[19]
            jaw_center = face_landmarks.landmark[152]
            eyebrow_center = face_landmarks.landmark[168]
            point1 = face_landmarks.landmark[10]#额头
            point2 = face_landmarks.landmark[151]#鼻梁
            point3 = face_landmarks.landmark[78]#下巴
            point4 = face_landmarks.landmark[308] # 下巴
            point5 = face_landmarks.landmark[175]  #
            point6 = face_landmarks.landmark[0]  #


    # 将坐标从相对坐标转换为图像坐标
    # nose_tip = (int(nose_tip.x * image.shape[1]), int(nose_tip.y * image.shape[0]))
    # jaw_center = (int(jaw_center.x * image.shape[1]), int(jaw_center.y * image.shape[0]))
    eyebrow_center = (int(eyebrow_center.x * image.shape[1]), int(eyebrow_center.y * image.shape[0]))
    # point1 = (int(point1.x * image.shape[1]), int(point1.y * image.shape[0]))
    # point2 = (int(point2.x * image.shape[1]), int(point2.y * image.shape[0]))
    point3 = (int(point3.x * image.shape[1]), int(point3.y * image.shape[0]))
    point4 = (int(point4.x * image.shape[1]), int(point4.y * image.shape[0]))
    point5 = (int(point5.x * image.shape[1]), int(point5.y * image.shape[0]))
    point6 = (int(point6.x * image.shape[1]), int(point6.y * image.shape[0]))

    # 计算中轴线方向并画出中轴线
    cv2.line(image, point5, point6, (0, 255, 0), 2)
    cv2.line(image, point3, point4, (0, 0, 255), 2)
    dis1=distance_point_to_line(point3, point5, point6)
    dis2=distance_point_to_line(point4, point5, point6)
    print('juli1',dis1)
    print('juli2',dis2)
    larger = max(dis1, dis2)
    smaller = min(dis1, dis2)

    # 判断是否异常
    if larger / smaller > 1.16:
        result ='嘴角歪斜'
    else:
        result = '正常'
    print(larger / smaller)
    # A, B, C = line_equation(point5, point6)
    # points = [point5, point6]
    # m, c = fit_line(points)
    # print(m,c)

    # # 确定线段的 x 范围
    # y_min = min(p[1] for p in points)
    # y_max = max(p[1] for p in points)


    # 绘制直线段
    # plot_line_segment(image, m, c, y_min, y_max)

    # 画中轴线两端点
    # cv2.circle(image, point1, 5, (0, 0, 255), -1)
    # cv2.circle(image, point2, 5, (0, 0, 255), -1)
    # cv2.circle(image, point3, 5, (0, 0, 255), -1)
    # cv2.circle(image, point4, 5, (0, 0, 255), -1)
    # cv2.circle(image, eyebrow_center, 5, (0, 0, 255), -1)
    # cv2.circle(image, jaw_center, 5, (0, 0, 255), -1)

    # reflected_points = []
    # for point in lip_landmarks:
    #     x, y = point
    #     # x_reflected, y_reflected = reflect_point_around_line(x, y, 10000, -1, 0)
    #     x_reflected = 2*eyebrow_center[0]-x
    #     y_reflected= y
    #     x_reflected = int(round(x_reflected))
    #     y_reflected = int(round(y_reflected))
    #     # 绘制对称点
    #     # cv2.circle(image, (x_reflected, y_reflected), 2, (0, 255, 0), -1)
    #     reflected_points.append((x_reflected, y_reflected))
    #     # 你可以打印或进一步处理对称点和距离
    #
    # distance_sum = calculate_total_distance(lip_landmarks, reflected_points)
    # print("Total Distance Sum:", distance_sum)

    # # 显示处理后的图片
    # cv2.imshow('Processed Image', image)
    #
    # # 等待用户按键后关闭显示窗口
    # cv2.waitKey(0)  # 0 表示无限等待，直到按下任何键
    # cv2.destroyAllWindows()  # 关闭所有打开的窗口
    #
    # # 保存处理后的图片
    # cv2.imwrite('face_result.jpg', image)

    # if(distance_sum>300):
    #     result ='嘴角歪斜'
    # else:
    #     result = '正常'
    #
    return result,image


if __name__ == '__main__':
    image_path='./test_data/face.jpg'
    result,image=lipClassification(image_path)
    # cv2.imshow('image',image)
    # cv2.waitKey(0)  # 0 表示无限等待，直到按下任何键
    # cv2.destroyAllWindows()  # 关闭所有打开的窗口